﻿package zdc.ui {
import com.greensock.TweenLite;

import flash.display.DisplayObject;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.getTimer;

import zdc.CollectionUtil;
import zdc.misc.Direction;
import zdc.Util;

/**
 *
 * @author Metal Slime
 */
public class MovingInertia {
    //walk模式
    protected var _WALK_TYPE:Boolean = false;
    //是否可用
    protected var _enable:Boolean = true;
    //接受鼠标对象
    protected var _evtTarget:DisplayObject;
    //执行动作对象
    protected var _actTarget:DisplayObject;
    //上次按下时间
    protected var _ltime:Number = 0;
    //按下弹起之间的时间
    protected var _ttime:Number = 0;
    //最大及最小缓动延迟时间
    protected var _maxDelay:Number = 3000;
    protected var _minDelay:Number = 100;
    //缓动类
    protected var _tw:TweenLite;
    //第一次，前一次，此次位移差, 总位移
    protected var _ox:Number, _oy:Number,
            _lx:Number, _ly:Number,
            _cdx:Number, _cdy:Number,
            _tdx:Number, _tdy:Number;
    //最小经过的距离
    protected var _minWalkDistX:int = 5;
    protected var _minWalkDistY:int = 5;
    protected var _curWalkDistX:int = 0, _curWalkDistY:int = 0;
    //方向
    protected var _dir:String = Direction.HORIZONTAL;
    //弹起，按下，移动的事件名
    protected var _dEvt:String, _uEvt:String, _mEvt:String, _oEvt:String;
    /**
     * 弹起，按下，移动，经过的函数
     */
    protected var _uFunHooks:Vector.<Function>;
    protected var _dFunHooks:Vector.<Function>;
    protected var _mFunHooks:Vector.<Function>;
    protected var _wFunHooks:Vector.<Function>;

    //检测是否可以移动的函数
    protected var _movableCheckFun:Function;

    /**
     * 自动销毁
     */
    protected var _autoDispose:Boolean = true;

    public function MovingInertia(evtTarget:DisplayObject, actTarget:DisplayObject = null, downEvt:String = "", upEvt:String = "", movEvt:String = "", outEvt:String = "", dir:String = "h", autoDispose:Boolean = true) {
        _evtTarget = evtTarget;
        _actTarget = actTarget || evtTarget;
        _dir = dir;

        _dEvt = downEvt;
        _uEvt = upEvt;
        _mEvt = movEvt;
        _oEvt = outEvt;

        _uFunHooks = new Vector.<Function>();
        _dFunHooks = new Vector.<Function>();
        _mFunHooks = new Vector.<Function>();
        _wFunHooks = new Vector.<Function>();

        _autoDispose = autoDispose;

        addEvts();
    }

    //当对象在舞台移除销毁此对象
    protected function onRemoved(e:Event):void {
        _actTarget.removeEventListener(Event.REMOVED_FROM_STAGE, onRemoved);
        _evtTarget.removeEventListener(Event.REMOVED_FROM_STAGE, onRemoved);
        dispose();
    }

    //按下处理器
    protected function onDown(e:Object = null):void {
        //最初坐标，上次坐标
        _ox = _lx = e.stageX;
        _oy = _ly = e.stageY;
        //当前位移，总共位移
        _cdx = _tdx = 0;
        _cdy = _tdy = 0;
        if (_movableCheckFun != null && !_movableCheckFun(e.stageX, e.stageY)) {
            remEvts();
            addDownEvt();
            return;
        }
        addMoveEvt();
        addUpEvt();
        addOutEvt();

        _ltime = getTimer();
        execDownHook(e);
    }

    //弹起处理器
    protected function onUp(e:Object = null):void {
        remMoveEvt();
        remOutEvt();
        remUpEvt();

        _curWalkDistX = _curWalkDistY = 0;
        var sx:Number = e.stageX;
        var sy:Number = e.stageY;
        _tdx = sx - _ox;
        _tdy = sy - _oy;
        _cdx = sx - _lx;
        _cdy = sy - _ly;
        _lx = sx;
        _ly = sy;
        _ttime = getTimer() - _ltime;
        execUpHook(e, _ttime, _tdx, _tdy);
        _tdx = _tdy = _ox = _oy = _cdx = _cdy = 0;
    }

    //移动处理器
    protected function onMove(e:Object = null):void {
        var sx:Number = e.stageX;
        var sy:Number = e.stageY;
        _cdx = sx - _lx;
        _cdy = sy - _ly;
        _lx = sx;
        _ly = sy;
        /**
         * 如果不是步增类型则使用移动
         */
        if (!_WALK_TYPE) {
            execMoveHook(e, _cdx, _cdy);
        }
        else {
            /**
             * 当前的所有距离相加
             */
            _curWalkDistX += _cdx;
            _curWalkDistY += _cdy;
            var canWalk:Boolean = false;
            if (isH) {
                canWalk = Math.abs(_curWalkDistX) >= _minWalkDistX;
            }
            if (isV) {
                canWalk = (Math.abs(_curWalkDistY) >= _minWalkDistY) && (!isH || canWalk);
            }
            if (canWalk) {
                execWalkHook(e, _curWalkDistX, _curWalkDistY);
                _curWalkDistX = _curWalkDistY = 0;
            }
        }
    }

    //移出处理器
    protected function onOut(e:Object = null):void {
        onUp(e);
        remUpEvt();
        remMoveEvt();
        remOutEvt();
    }

    //添加事件
    protected function addEvts():void {
        _actTarget.addEventListener(Event.REMOVED_FROM_STAGE, onRemoved);
        _evtTarget.addEventListener(Event.REMOVED_FROM_STAGE, onRemoved);

        addDownEvt();
    }

    private function addDownEvt():void {
        if (_dEvt) {
            _evtTarget.addEventListener(_dEvt, onDown);
        }
    }

    private function addUpEvt():void {
        if (_uEvt) {
            _evtTarget.addEventListener(_uEvt, onUp);
        }
    }

    private function addMoveEvt():void {
        if (_mEvt) {
            _evtTarget.addEventListener(_mEvt, onMove);
        }
    }

    private function addOutEvt():void {
        if (_oEvt) {
            _evtTarget.addEventListener(_oEvt, onOut);
        }
    }

    private function remDownEvt():void {
        if (_dEvt) {
            _evtTarget.removeEventListener(_dEvt, onDown);
        }
    }

    private function remUpEvt():void {
        if (_uEvt) {
            _evtTarget.removeEventListener(_uEvt, onUp);
        }
    }

    private function remMoveEvt():void {
        if (_mEvt) {
            _evtTarget.removeEventListener(_mEvt, onMove);
        }
    }

    private function remOutEvt():void {
        if (_oEvt) {
            _evtTarget.removeEventListener(_oEvt, onOut);
        }
    }

    //删除时间
    protected function remEvts():void {
        if (!_evtTarget) {
            return;
        }

        remDownEvt();
        remUpEvt();
        remMoveEvt();
        remOutEvt();
    }

    /**
     * 销毁惯性类
     */
    public function dispose():void {
        _tw && _tw.kill();
        _tw = null;
        remEvts();
        clearAllHooks();
        if (_autoDispose) {
            _actTarget = _evtTarget = null;
        }
    }

    /**
     * 是否需要水平
     */
    public function get isH():Boolean {
        return _dir.indexOf("h") > -1;
    }

    /**
     * 是否需要垂直
     */
    public function get isV():Boolean {
        return _dir.indexOf("v") > -1;
    }

    /**
     * 是否向左
     */
    public function get isLeft():Boolean {
        return _tdx < 0;
    }

    /**
     * 是否向左
     */
    public function get isRight():Boolean {
        return _tdx > 0;
    }

    /**
     * 是否向上
     */
    public function get isUp():Boolean {
        return _tdy < 0;
    }

    /**
     * 是否向下
     */
    public function get isDown():Boolean {
        return _tdy > 0;
    }

    public function get downEvt():String {
        return _dEvt;
    }

    /**
     * 清除所有钩子
     */
    public function clearAllHooks():void {
        clearDownHooks();
        clearMoveHooks();
        clearUpHooks();
        clearWalkHooks();
    }

    /**
     * 执行所有弹起钩子
     */
    public function execUpHook(e:Object, totalTime:Number, totalDistX:Number, totalDistY:Number):void {
        for (var i:int = 0; i < _uFunHooks.length; i++) {
            _uFunHooks[i] && _uFunHooks[i](e, totalTime, totalDistX, totalDistY);
        }
    }

    /**
     * 添加弹起钩子
     * @param    func
     */
    public function addUpHook(func:Function):void {
        if (_uFunHooks.indexOf(func) == -1) {
            _uFunHooks.push(func);
        }
    }

    /**
     * 删除按下钩子
     * @param    func
     */
    public function remUpHook(func:Function):void {
        CollectionUtil.removeItems(_uFunHooks, func);
    }

    /**
     * 清除弹起钩子
     */
    public function clearUpHooks():void {
        CollectionUtil.clear(_uFunHooks);
    }

    /**
     * 执行所有按下钩子
     */
    public function execDownHook(e:Object):void {
        for (var i:int = 0; i < _dFunHooks.length; i++) {
            _dFunHooks[i] && _dFunHooks[i](e);
        }
    }

    /**
     * 添加按下钩子
     * @param    func
     */
    public function addDownHook(func:Function):void {
        if (_dFunHooks.indexOf(func) == -1) {
            _dFunHooks.push(func);
        }
    }

    /**
     * 删除按下钩子
     * @param    func
     */
    public function remDownHook(func:Function):void {
        CollectionUtil.removeItems(_dFunHooks, func);
    }

    /**
     * 清除按下钩子
     */
    public function clearDownHooks():void {
        CollectionUtil.clear(_dFunHooks);
    }

    /**
     * 执行所有移动钩子
     */
    public function execMoveHook(e:Object, totalDistX:Number, totalDistY:Number):void {
        for (var i:int = 0; i < _mFunHooks.length; i++) {
            _mFunHooks[i] && _mFunHooks[i](e, totalDistX, totalDistY);
        }
    }

    /**
     * 添加移动钩子
     * @param    func
     */
    public function addMoveHook(func:Function):void {
        if (_mFunHooks.indexOf(func) == -1) {
            _mFunHooks.push(func);
        }
    }

    /**
     * 删除移动钩子
     * @param    func
     */
    public function remMoveHook(func:Function):void {
        CollectionUtil.removeItems(_mFunHooks, func);
    }

    /**
     * 清除按下钩子
     */
    public function clearMoveHooks():void {
        CollectionUtil.clear(_mFunHooks);
    }

    /**
     * 执行所有经过钩子
     */
    public function execWalkHook(e:Object, totalDistX:Number, totalDistY:Number):void {
        for (var i:int = 0; i < _wFunHooks.length; i++) {
            _wFunHooks[i] && _wFunHooks[i](e, totalDistX, totalDistY);
        }
    }

    /**
     * 添加经过钩子
     * @param    func
     */
    public function addWalkHook(func:Function):void {
        if (_wFunHooks.indexOf(func) == -1) {
            _wFunHooks.push(func);
        }
    }

    /**
     * 删除经过钩子
     * @param    func
     */
    public function remWalkHook(func:Function):void {
        CollectionUtil.removeItems(_wFunHooks, func);
    }

    /**
     * 清除经过钩子
     */
    public function clearWalkHooks():void {
        CollectionUtil.clear(_wFunHooks);
    }

    public function set downEvt(value:String):void {
        _dEvt && _evtTarget.removeEventListener(_dEvt, onDown);
        _dEvt = value;
        _dEvt && _evtTarget.addEventListener(_dEvt, onDown);

    }

    public function get upEvt():String {
        return _uEvt;
    }

    public function set upEvt(value:String):void {
        _uEvt && _evtTarget.removeEventListener(_uEvt, onUp);
        _uEvt = value;
        _uEvt && _evtTarget.addEventListener(_uEvt, onUp);
    }

    public function get outEvt():String {
        return _oEvt;
    }

    public function set outEvt(value:String):void {
        _oEvt && _evtTarget.removeEventListener(_oEvt, onOut);
        _oEvt = value;
        _oEvt && _evtTarget.addEventListener(_oEvt, onOut);
    }

    public function get moveEvt():String {
        return _mEvt;
    }

    public function set moveEvt(value:String):void {
        _mEvt && _evtTarget.removeEventListener(_mEvt, onMove);
        _mEvt = value;
        _mEvt && _evtTarget.addEventListener(_mEvt, onMove);
    }

    /**
     * 是否可用
     */
    public function get enable():Boolean {
        return _enable;
    }

    public function set enable(value:Boolean):void {
        if (value) {
            addEvts();
        }
        else {
            remEvts();
        }
        _enable = value;
    }

    public function get WALK_TYPE():Boolean {
        return _WALK_TYPE;
    }

    public function set WALK_TYPE(value:Boolean):void {
        _WALK_TYPE = value;
    }

    public function get minWalkDistX():int {
        return _minWalkDistX;
    }

    public function set minWalkDistX(value:int):void {
        _minWalkDistX = value;
    }

    public function get minWalkDistY():int {
        return _minWalkDistY;
    }

    public function set minWalkDistY(value:int):void {
        _minWalkDistY = value;
    }

    public function get dir():String {
        return _dir;
    }

    public function set dir(value:String):void {
        _dir = value;
    }

    public function get autoDispose():Boolean {
        return _autoDispose;
    }

    public function set autoDispose(value:Boolean):void {
        _autoDispose = value;
    }

    public function get movableCheckFun():Function {
        return _movableCheckFun;
    }

    public function set movableCheckFun(value:Function):void {
        _movableCheckFun = value;
    }
}

}